package agent

import (
	"bytes"
	"context"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"gitee.com/shiwjlinux/arm/apps/host"
	clients "gitee.com/shiwjlinux/arm/clients/restful"
	"gitee.com/shiwjlinux/arm/common"
	"gitee.com/shiwjlinux/arm/conf"
	"github.com/rs/zerolog"
)

var ctx context.Context

type HostAgent struct {
	client   *clients.Client
	interval time.Duration
	// sn       string
	Host *host.Host
	// lastInfo *host.CreateHostRequest // 添加lastInfo缓存
	stopChan chan struct{}
	logger   *zerolog.Logger
}

func NewHostAgent(client *clients.Client, interval time.Duration) (*HostAgent, error) {
	// logger := conf.C().Logger.GetLogger().With().Str("component", "host_agent").Logger()
	logger := conf.C().Log.Logger().With().Str("component", "host_agent").Logger()
	sn, err := GetHostSn()
	if err != nil {
		return nil, err
	}
	agent := &HostAgent{
		client:   client,
		interval: interval,
		stopChan: make(chan struct{}),
		logger:   &logger,
		Host:     host.DefaultHost(),
	}

	agent.client.Debug(false)

	// 初始化时先注册主机
	if err := agent.registerHost(sn); err != nil {
		return nil, err
	}

	return agent, nil
}

// 获取主机序列号
func GetHostSn() (string, error) {
	// getprop ro.boot.serialno

	if common.IsAndroid() {
		// 执行 getprop 命令以获取序列号
		cmd := exec.Command("getprop", "ro.boot.serialno")
		var out bytes.Buffer
		cmd.Stdout = &out
		if err := cmd.Run(); err != nil {
			return "", err
		}
		sn := out.String()
		return sn, nil
	}

	// 在其他平台上获取主机名
	sn, err := os.Hostname()
	return sn, err
}

func getHostIp() (string, error) {
	ips, err := common.GetHostIPs()
	if err != nil {
		return "", err
	}
	return strings.Join(ips, ","), nil
}

// getprop ro.build.version.name
func GetBuildVersion() (string, error) {
	// return "test", nil
	cmd := exec.Command("getprop", "ro.build.version.name")
	var out bytes.Buffer
	cmd.Stdout = &out
	if err := cmd.Run(); err != nil {
		return "", err
	}
	return out.String(), nil
}

// 注册主机
func (a *HostAgent) registerHost(sn string) error {
	queryReq := host.
		NewQueryHostRequest().
		WithSn(sn)
	// queryReq.Sn = sn

	set, err := a.client.QueryHost(ctx, queryReq)
	if err != nil {
		return err
	}
	// 如果主机已存在，则直接返回
	if set.Total != 0 {
		a.Host = set.Items[0]
		a.logger.Info().Msgf("query host success, id %d", a.Host.Id)
		return nil
	}

	// 如果主机不存在，则创建主机
	a.logger.Info().Msgf("create host ...")
	creqteReq := host.NewCreateHostRequest(sn, "")
	h, err := a.client.CreateHost(ctx, creqteReq)
	if err != nil {
		return err
	}
	a.Host = h
	return nil
}

func (a *HostAgent) Start() {
	a.logger.Info().Msgf("start host agent ...")
	go a.runReportLoop()
}

func (a *HostAgent) runReportLoop() {
	// 启动时立即执行一次上报
	if err := a.reportHostInfo(); err != nil {
		log.Printf("Initial host info report failed: %v", err)
	}

	ticker := time.NewTicker(a.interval)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if err := a.reportHostInfo(); err != nil {
				log.Printf("Failed to report host info: %v", err)
			}
		case <-a.stopChan:
			return
		}
	}
}

// Stop 停止
func (a *HostAgent) Stop() {
	a.logger.Info().Msgf("stop host agent ...")
	// 更新主机状态为离线
	if a.Host != nil {
		updateReq := host.NewUpdateHostRequestById(strconv.FormatInt(a.Host.Id, 10))
		updateReq.Status = host.STATUS_OFFLINE

		if _, err := a.client.UpdateHost(ctx, updateReq); err != nil {
			a.logger.Error().Err(err).Msg("failed to update host status to offline")
		}
	}

	close(a.stopChan)
	a.logger.Info().Msg("host agent stopped")
}

// 对比主机信息是否有更新
func (a *HostAgent) isInfoChanged(newInfo *host.CreateHostRequest) bool {
	if a.Host == nil {
		return true
	}
	return a.Host.CreateHostRequest.Hash() != newInfo.Hash()
}

// 上报主机信息
func (a *HostAgent) reportHostInfo() error {
	// 收集当前主机信息
	newInfo := a.collectHostInfo()
	// 检查信息是否发生变化
	if !a.isInfoChanged(newInfo) {
		a.logger.Debug().Msg("host info not changed, skip update")
		return nil
	}
	// 信息有变化 ，执行更新

	updateReq := &host.UpdateHostRequest{
		Id: strconv.FormatInt(a.Host.Id, 10),
		CreateHostRequest: &host.CreateHostRequest{
			Sn:           newInfo.Sn,
			Status:       newInfo.Status,
			Summary:      newInfo.Summary,
			CreateBy:     newInfo.CreateBy,
			Ip:           newInfo.Ip,
			Hostname:     newInfo.Hostname,
			Type:         newInfo.Type,
			BuildVersion: newInfo.BuildVersion,
		},
	}

	updatedHost, err := a.client.UpdateHost(ctx, updateReq)
	if err != nil {
		return err
	}
	a.Host = updatedHost
	a.logger.Debug().Msg("host info updated successfully")

	return nil
}

// 收集主机信息
func (a *HostAgent) collectHostInfo() *host.CreateHostRequest {
	hostname, _ := os.Hostname()
	sn, _ := GetHostSn()
	ip, _ := getHostIp()
	bv, _ := GetBuildVersion()
	return &host.CreateHostRequest{
		Hostname:     hostname,
		Sn:           sn,
		Status:       host.STATUS_ONLINE,
		Summary:      "",
		CreateBy:     sn,
		Ip:           ip,
		Type:         "",
		BuildVersion: bv,
	}
}
